home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 5 / Amiga Tools 5.iso / internet-tools / amitcp / amitcp-sdk-4.3 / src / examples / httpget / httpget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-02  |  7.0 KB  |  359 lines

  1. /*
  2.  * $Id: httpget.c $
  3.  *
  4.  *     Copyright (c) 1996 Network Solutions Development Inc.
  5.  *             All rights reserved
  6.  *
  7.  * Created: Thu Feb 15 22:12:54 1996 too
  8.  * Last modified: Sat Mar  2 17:18:00 1996 too
  9.  *
  10.  * HISTORY 
  11.  * $Log: $
  12.  */
  13.  
  14. /*
  15.  * To make sure no code can get run before `start'.
  16.  */
  17.  
  18. int start(void);
  19. int begin(void) { return start(); }
  20.  
  21. #include <exec/types.h>
  22.  
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/socket.h>
  26. /*#include <proto/usergroup.h> */
  27.  
  28. struct ExecBase * SysBase;
  29. struct DosLibrary * DOSBase;
  30. struct Library * SocketBase;
  31.  
  32.  
  33. /* general system / socket includes */
  34. #include <sys/types.h>
  35. #include <sys/socket.h>
  36.  
  37. /* internet socket stuff */
  38. #include <netinet/in.h>
  39.  
  40. /* host name resolvation/database stuff */
  41. #include <netdb.h>
  42.  
  43. /*
  44.  *
  45.  */
  46.  
  47. /* #define PutCS(s) Write(Output(), s, sizeof (s) - 1) */
  48.  
  49. #define TEMPLATE "URL/A"
  50.  
  51. /*
  52.  * My 'startup code' initialize bases, read arguments and call `main'
  53.  * httpget -routine.
  54.  */
  55. int httpget(char * url);
  56.  
  57. #ifdef __GNUC__
  58. /* saveds is used in SASC to get global data base pointer. SAS/C compiles
  59.    base relative code by default, which makes target binary somewhat smaller */
  60. #define __saveds
  61. #endif
  62.  
  63. int __saveds start()
  64. {
  65.   int rv = 20;    /* default exit value */
  66.   SysBase = *(struct ExecBase **)4;
  67.  
  68.   if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37)) != NULL)
  69.   {
  70.     if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) != NULL)
  71.     {
  72.       struct RDArgs * rdargs;
  73.       char * Argv[1] = { 0 };
  74.       
  75.       if ((rdargs = ReadArgs(TEMPLATE, (LONG *)Argv, NULL)) != NULL)
  76.       {
  77.     rv = httpget(Argv[0]);
  78.     FreeArgs(rdargs);
  79.       }
  80.       else
  81.     Printf("Usage: httpget " TEMPLATE "\n");
  82.  
  83.       CloseLibrary(SocketBase);
  84.     }
  85.     else
  86.       Printf("Cannot open bsdsocket.library\n");
  87.  
  88.     CloseLibrary((struct Library *)DOSBase);
  89.   }
  90.   return rv;
  91. }
  92.  
  93. /*
  94.  * Since this is a no-link-libraries -example, we have to write all the
  95.  * most trivial functions ourselves. It would be wise to use standard
  96.  * c-link-library for these, but just skip startup code.
  97.  * (optimized library functions are the smallest and fastest possible)
  98.  */
  99.  
  100. void bzero(char * p, int len)
  101. {
  102.   while (len--)
  103.     *p++ = '\0';
  104. }
  105.  
  106. int memcmp(char * s1, char * s2, int n)
  107. {
  108.   int c;
  109.  
  110.   while (n--)
  111.     if ((c = (*s1++ - *s2++)) != 0)
  112.       return c;
  113.  
  114.   return 0;
  115. }
  116.  
  117. #if 1
  118. #define memcpy(a,b,c) CopyMem((b),(a),(c))
  119. #else
  120. void memcpy(char * d, char * s, int l)
  121. {
  122.   while (l)
  123.   {
  124.     l--;
  125.     *d++ = *s++;
  126.   }
  127. }
  128. #endif
  129.  
  130. int strlen(char * str)
  131. {
  132.   int i = 0;
  133.  
  134.   while (*str) {
  135.     str++;
  136.     i++;
  137.   }
  138.   return i;
  139. }  
  140.  
  141.  
  142. char * strchr(char * string, char c)
  143. {
  144.   while (*string)
  145.     if (*string == c)
  146.       return string;
  147.     else
  148.       string++;
  149.  
  150.   return NULL;
  151. }
  152.  
  153. char * strstr(char * string, char * s)
  154. {
  155.   while (*string)
  156.     if (strchr(s, *string) != NULL)
  157.       return string;
  158.     else
  159.       string++;
  160.   
  161.   return NULL;
  162. }
  163.  
  164. int isdigit(char c)
  165. {
  166.   return (c >= '0' && c <= '9');
  167. }
  168.  
  169. int atoi(char * str)
  170. {
  171.   int i = 0;
  172.  
  173.   while (isdigit(*str))
  174.     i = i * 10 + *str++ - '0';
  175.  
  176.   return i;
  177. }
  178.  
  179. /*
  180.  * Let's define some useful routines for this application.
  181.  */
  182.  
  183. static int printUrlFault(void)
  184. {
  185.   Printf("Url has to have format: [http://]host.domain.net[:port]/path\n");
  186.   return 20;
  187. }
  188.  
  189.  
  190. /*
  191.  * And finally to our `main' routines.
  192.  */
  193. static int    do_connect(char * name, int port);
  194. static void    netperror(char * banner);
  195.  
  196. int httpget(char * url)
  197. {
  198.   char buf[1024]; /*stack usage of program should fit in 4000 bytes of memory*/
  199.   char * p, * u;  /* ^^^ in current program 1k local buffer is sufficient */
  200.   int i, port, sd;
  201.  
  202.   /*
  203.    * A URL may start w/ http:// or without it in this application.
  204.    */ 
  205.   if (memcmp(url, "http://", 7) == 0)
  206.     url+= 7;
  207.   
  208.   if ((p = strstr(url, ":/")) == NULL)
  209.     return printUrlFault();
  210.  
  211.   if (*p == ':') {
  212.     /*
  213.      * user want's to access custom port/service.
  214.      */
  215.     u = strchr(p, '/');
  216.  
  217.     if (u == NULL)
  218.       return printUrlFault();
  219.  
  220.     if (u == p) {
  221.       Printf("No port/service defined\n");
  222.       return 20;
  223.     }
  224.     /*
  225.      * But now, I'm too lazy to write full `getservbyname' query here,
  226.      * so only numeric port information will do
  227.      */
  228.     if ((port = atoi(p+1)) == 0) {
  229.       Printf("Given port not numeric\n");
  230.       return 20;
  231.     }
  232.   }
  233.   else {
  234.     u = p;
  235.     port = 80;    /* standard http -service port number */
  236.   }
  237.  
  238.   *p = '\0';
  239.  
  240.   if ((sd = do_connect(url, port)) < 0)
  241.     return 20;
  242.  
  243.   *p = '/';
  244.   /*
  245.    * I could have done a hack to write "GET " at position u - 4 and done
  246.    * a single send() call to peer. I don't know a hostname that fits in 3
  247.    * bytes and get positive answer from name server. Anyway, that would
  248.    * have been too `kludgy' way to solve the problem in this example.
  249.    */
  250.  
  251.   i = strlen(u);
  252.   u[i++] = '\n'; /* here it is safe to replace terminating NUL w/ '\n';
  253.   
  254. /*  Printf("Sending `%s'\n",u); */
  255.   /*
  256.    * unless fails, send will send all bytes, since in NONBLOCKing mode
  257.    */
  258.   if ((send(sd, "GET ", 4, 0) != 4) || (send(sd, u, i, 0) != i)) {
  259.     netperror("send");
  260.     return 20;
  261.   }
  262.  
  263.   while ((i = recv(sd, buf, sizeof buf, 0)) > 0)
  264.     Write(Output(), buf, i);
  265.  
  266.   if (i != 0) {
  267.     netperror("recv");
  268.     return 20;
  269.   }
  270.   
  271.   return 0;
  272. }
  273.  
  274. /*
  275.  * Stuff to make connection. Reuse freely.
  276.  */
  277. int
  278. getSockAddr(const char *     host,
  279.         int             port,
  280.         struct sockaddr_in * addr)
  281. {
  282.   struct hostent * remote;
  283.  
  284.   if ((remote = gethostbyname(host)) != NULL)
  285.     memcpy(&addr->sin_addr, remote->h_addr, sizeof addr->sin_addr);
  286.   else if ((addr->sin_addr.s_addr = inet_addr(host)) == (unsigned long)-1) {
  287.     return FALSE;
  288.   }
  289.  
  290.   addr->sin_port = htons(port);
  291.   addr->sin_family = AF_INET;
  292.  
  293.   return TRUE;
  294. }
  295.  
  296. const int ONE = 1;
  297.  
  298. int inetconn (const struct sockaddr_in * addr)
  299. {
  300.   int sd;
  301.  
  302.   if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  303.     netperror ("socket");
  304.     return -1;
  305.   }
  306.   
  307.   setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &ONE, sizeof ONE);
  308.     
  309.   if (connect(sd, (struct sockaddr *)addr, sizeof (struct sockaddr_in)) < 0) {
  310.     CloseSocket(sd);
  311.     netperror("connect");
  312.     return -1;
  313.   }
  314.  
  315.   return sd;
  316. }
  317.  
  318.  
  319. static int do_connect(char * host, int port)
  320. {
  321.   struct sockaddr_in
  322.     addr = { 0 }; /* implicit bzero() here when compiled w/ gcc */
  323.   
  324.   if (getSockAddr(host, port, &addr) == FALSE) {
  325.     Printf("Cannot resolve host address\n");
  326.     return -1;
  327.   }
  328.  
  329.   return inetconn(&addr);
  330. }
  331.   
  332.  
  333. /*
  334.  * This `perror' works only for sockets. Therefore hidden here at the end
  335.  * of this program. There is a general perror function available in network
  336.  * link library without any additional speed/size overhead. This is used to
  337.  * demonstrate the power of `SocketBaseTagList()' function.
  338.  */
  339.  
  340. #include <amitcp/socketbasetags.h>
  341.  
  342. static void netperror(char * banner)
  343. {
  344.   ULONG taglist[5];
  345.   
  346.   taglist[0] = SBTM_GETVAL(SBTC_ERRNO);
  347.   /* taglist[1] set when tag 0 executed */
  348.   taglist[2] = SBTM_GETREF(SBTC_ERRNOSTRPTR);
  349.   taglist[3] = (LONG)&taglist[1]; /* reads and writes tag[1] */
  350.   taglist[4] = NULL;    /* TAG_END if <utility/tagitem> is included */
  351.  
  352.   SocketBaseTagList((struct TagItem *)taglist);
  353.  
  354.   if (banner)
  355.     Printf("%s:", banner);
  356.  
  357.   Printf("%s\n", (char *)taglist[1]);
  358. }
  359.